<i18n locale="en" lang="yaml">
uploadCost    : '{s} s'
uploadCostLong: '{m} min {s} s'
</i18n>
<i18n locale="zh-CN" lang="yaml">
Go Top         : 返回顶层
Go Up          : 向上
File size limit: 文件大小限制
Path           : 路径
Create time    : 创建时间
Update time    : 更新时间

Temp Folder for Upload                             : 用于上传的临时目录
Temp Folder for Download                           : 用于下载的临时目录
Python Package Folder for Installation via PIP Tool: 通过 PIP 工具安装的 Python 包目录
Python Package Folder for Local Usage by User      : 用户本地使用的 Python 包目录
Data Folder for Script Market                      : 脚本市场数据目录
Pre-Run Script Folder                              : 预执行脚本目录

Unarchive     : 解压
Archive in zip: 压缩为 zip
Archive in 7z : 压缩为 7z
Archive in tar: 压缩为 tar
Package       : Wheel 包
PIP Mirror    : PIP 镜像

File uploaded                    : 文件已上传
'Wheel package installed: {name}': Wheel 包已安装：{name}

Please input destination path                                                        : 请输入目标路径
'File <code class="text-main">{name}</code> already existed, please input a new name': '文件 <code class="text-main">{name}</code> 已经存在，请输入新文件名'
Install Wheel package                                                                : 安装 Wheel 包
Are you sure you want to delete the content?                                         : 是否确定删除此内容？
Delete file                                                                          : 删除文件
File already existed                                                                 : 文件已经存在

'File too large (size limit: {size})': '文件过大（大小限制：{size}）'
'Uploading {filename}'               : '正在上传 {filename}'
'Processing...'                      : '正在处理...'

Cost          : 耗时
Remain        : 剩余
uploadCost    : '{s} 秒'
uploadCostLong: '{m} 分 {s} 秒'
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Archive in 7z: 壓縮為 7z
Archive in tar: 壓縮為 tar
Archive in zip: 壓縮為 zip
Are you sure you want to delete the content?: 是否確定刪除此內容？
Cost: 耗時
Create time: 創建時間
Data Folder for Script Market: 腳本市場數據目錄
Delete file: 刪除文件
File <code class="text-main">{name}</code> already existed, please input a new name: 文件 <code class="text-main">{name}</code> 已經存在，請輸入新文件名
File already existed: 文件已經存在
File size limit: 文件大小限制
'File too large (size limit: {size})': 文件過大（大小限制：{size}）
File uploaded: 文件已上傳
Go Top: 返回頂層
Go Up: 向上
Install Wheel package: 安裝 Wheel 包
PIP Mirror: PIP 鏡像
Package: Wheel 包
Path: 路徑
Please input destination path: 請輸入目標路徑
Pre-Run Script Folder: 預執行腳本目錄
Processing...: 正在處理...
Python Package Folder for Installation via PIP Tool: 通過 PIP 工具安裝的 Python 包目錄
Python Package Folder for Local Usage by User: 用户本地使用的 Python 包目錄
Remain: 剩餘
Temp Folder for Download: 用於下載的臨時目錄
Temp Folder for Upload: 用於上傳的臨時目錄
Unarchive: 解壓
Update time: 更新時間
Uploading {filename}: 正在上傳 {filename}
'Wheel package installed: {name}': Wheel 包已安裝：{name}
uploadCost: '{s} 秒'
uploadCostLong: '{m} 分 {s} 秒'
</i18n>
<i18n locale="zh-TW" lang="yaml">
Archive in 7z: 壓縮為 7z
Archive in tar: 壓縮為 tar
Archive in zip: 壓縮為 zip
Are you sure you want to delete the content?: 是否確定刪除此內容？
Cost: 耗時
Create time: 建立時間
Data Folder for Script Market: 指令碼市場資料目錄
Delete file: 刪除檔案
File <code class="text-main">{name}</code> already existed, please input a new name: 檔案 <code class="text-main">{name}</code> 已經存在，請輸入新檔名
File already existed: 檔案已經存在
File size limit: 檔案大小限制
'File too large (size limit: {size})': 檔案過大（大小限制：{size}）
File uploaded: 檔案已上傳
Go Top: 返回頂層
Go Up: 向上
Install Wheel package: 安裝 Wheel 包
PIP Mirror: PIP 映象
Package: Wheel 包
Path: 路徑
Please input destination path: 請輸入目標路徑
Pre-Run Script Folder: 預執行指令碼目錄
Processing...: 正在處理...
Python Package Folder for Installation via PIP Tool: 透過 PIP 工具安裝的 Python 包目錄
Python Package Folder for Local Usage by User: 使用者本地使用的 Python 包目錄
Remain: 剩餘
Temp Folder for Download: 用於下載的臨時目錄
Temp Folder for Upload: 用於上傳的臨時目錄
Unarchive: 解壓
Update time: 更新時間
Uploading {filename}: 正在上傳 {filename}
'Wheel package installed: {name}': Wheel 包已安裝：{name}
uploadCost: '{s} 秒'
uploadCostLong: '{m} 分 {s} 秒'
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <transition name="fade">
    <el-container direction="vertical" v-show="$store.state.isLoaded"
      v-loading.fullscreen.lock="isProcessing"
      element-loading-spinner="el-icon-loading"
      :element-loading-text="progressTip || $t('Processing...')">
      <!-- Header area -->
      <el-header height="60px">
        <div class="common-page-header">
          <div>
            <h1>{{ $t('File Manager') }}</h1>
            &#12288;
            <el-tooltip :content="$t('Go Up')">
              <el-button @click="enterFolder('..')" :disabled="currentFolder === '/'" size="small">
                <i class="fa fa-fw fa-arrow-up"></i>
              </el-button>
            </el-tooltip>
            <el-tooltip :content="$t('Refresh')">
              <el-button @click="loadData({ isRefresh: true })" size="small" class="fix-compact-button">
                <i class="fa fa-fw fa-refresh"></i>
              </el-button>
            </el-tooltip>

            &#12288;
            <el-popover placement="bottom" width="240" v-model="showMkdirPopover">
              <div class="popover-input">
                <el-input ref="mkdirName" size="small" v-model="mkdirName" @keyup.enter.native="resourceOperation(mkdirName, 'mkdir')"></el-input>
                <el-button type="text" @click="resourceOperation(mkdirName, 'mkdir')">{{ $t('Add') }}</el-button>
              </div>
              <el-button slot="reference" size="small">
                <i class="fa fa-fw fa-plus"></i>
                {{ $t('Folder') }}
              </el-button>
            </el-popover>

            <el-tooltip :content="`${$t('File size limit')}${$t(':')}${T.byteSizeHuman($store.getters.SYSTEM_INFO('_RESOURCE_UPLOAD_FILE_SIZE_LIMIT'))}`" placement="bottom">
              <el-upload ref="upload"
                class="upload-button"
                :limit="2"
                :multiple="false"
                :auto-upload="true"
                :show-file-list="false"
                :http-request="handleUpload"
                :on-change="onUploadFileChange"
                action="">
                <el-button size="small">
                  <i class="fa fa-fw fa-cloud-upload"></i>
                  {{ $t('Upload') }}
                </el-button>
              </el-upload>
            </el-tooltip>

            &#12288;
            <code class="resource-navi" v-if="currentFolder !== '/'">
              <small>{{ $t('Path') }}{{ $t(':') }}</small>
              <el-button size="small" @click="enterFolder()">
                <i class="fa fa-fw fa-home"></i>
              </el-button><template v-for="(layer, index) in currentFolder.slice(1).split('/')">
                <div class="path-sep"><i class="fa fa-angle-right"></i></div><el-button
                  :key="index"
                  size="small"
                  @click="enterFolder(currentFolder.split('/').slice(0, index + 2).join('/'), true)">
                  {{ layer }}
                </el-button>
              </template>
            </code>
          </div>
          <div class="header-control">
          </div>
        </div>
      </el-header>

      <!-- List area -->
      <el-main class="common-table-container">
        <el-table
          class="common-table" height="100%"
          :data="files">
          <el-table-column :label="$t('Name')" sortable sort-by="name">
            <template slot-scope="scope">
              <el-link v-if="scope.row.type === 'folder'" @click="enterFolder(scope.row.name)">
                <i :class="`fa fa-fw fa-${scope.row.icon} fa-2x`"></i>
                <code class="file-folder-name">{{ scope.row.name }}/</code>
              </el-link>
              <template v-else>
                <el-link type="default"
                  :href="scope.row.downloadURL"
                  :download="scope.row.name"
                  target="_blank">
                  <i :class="`fa fa-fw fa-${scope.row.icon} fa-2x`"></i>
                  <code class="file-folder-name">{{ scope.row.name }}</code>
                  </el-link>
              </template>

              <template v-if="scope.row.tip">
                <br><small><i>{{ scope.row.tip }}</i></small>
              </template>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Create time')" sortable sort-by="createTime" width="200">
            <template slot-scope="scope">
              <template v-if="scope.row.createTime">
                <span>{{ scope.row.createTime | datetime }}</span>
                <br>
                <span class="text-info">{{ scope.row.createTime | fromNow }}</span>
              </template>
              <template v-else>
                -
              </template>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Update time')" sortable sort-by="updateTime" width="200">
            <template slot-scope="scope">
              <span>{{ scope.row.updateTime | datetime }}</span>
              <br>
              <span class="text-info">{{ scope.row.updateTime | fromNow }}</span>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Size')" sortable sort-by="size" align="right" width="120">
            <template slot-scope="scope">
              <code v-if="scope.row.size">{{ scope.row.sizeHuman }}</code>
            </template>
          </el-table-column>

          <el-table-column align="right" width="180">
            <template slot-scope="scope">
              <template v-if="scope.row.type === 'file'">
                <el-link v-if="archiveExts.includes(scope.row.ext)"
                  @click="resourceOperation(scope.row.name, 'unarchive')">{{ $t('Unarchive') }}</el-link>

                <el-link
                  v-if="previewExts.includes(scope.row.ext) || !scope.row.ext"
                  :href="scope.row.previewURL"
                  target="_blank">{{ $t('Open') }}</el-link>

                <el-link v-if="scope.row.ext === 'whl'"
                  @click="openInstallWheel(scope.row.name)">{{ $t('Install') }}</el-link>
              </template>

              <el-dropdown @command="resourceOperationCmd" trigger="click">
                <el-link>
                  {{ $t('More') }}
                  <i class="el-icon-arrow-down el-icon--right"></i>
                </el-link>
                <el-dropdown-menu slot="dropdown">
                  <template v-if="!archiveExts.includes(scope.row.ext)">
                    <el-dropdown-item :command="{ data: scope.row, operation: 'zip' }">
                      {{ $t('Archive in zip') }}
                    </el-dropdown-item>
                    <el-dropdown-item :command="{ data: scope.row, operation: 'tar' }">
                      {{ $t('Archive in tar') }}
                    </el-dropdown-item>
                    <el-dropdown-item :command="{ data: scope.row, operation: '7z' }">
                      {{ $t('Archive in 7z') }}
                    </el-dropdown-item>
                  </template>
                  <el-dropdown-item :divided="!archiveExts.includes(scope.row.ext)" :command="{ data: scope.row, operation: 'cp' }">
                    {{ $t('Copy') }}
                  </el-dropdown-item>
                  <el-dropdown-item :command="{ data: scope.row, operation: 'mv' }">
                    {{ $t('Move') }}
                  </el-dropdown-item>
                  <el-dropdown-item divided class="text-bad" :command="{ data: scope.row, operation: 'rm' }">
                    {{ $t('Delete') }}
                  </el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
            </template>
          </el-table-column>
        </el-table>
      </el-main>

      <el-dialog
        :title="$t('Install Wheel package')"
        width="30%"
        :visible.sync="showInstallWheel">
        <div>
          <el-form ref="form" label-width="80px">
            <el-form-item :label="$t('Package')">
              <el-input :disabled="true" :value="wheelToInstall"></el-input>
            </el-form-item>

            <el-form-item :label="$t('PIP Mirror')">
              <el-select v-model="pipIndexURL">
                <el-option v-for="mirror in C.PIP_MIRROR" :label="mirror.name" :key="mirror.key" :value="mirror.value"></el-option>
              </el-select>
            </el-form-item>
          </el-form>
        </div>
        <div slot="footer">
          <el-button @click="showInstallWheel = false">{{ $t('Cancel') }}</el-button>
          <el-button type="primary" @click="installWheel">{{ $t('Install') }}</el-button>
        </div>
      </el-dialog>
    </el-container>
  </transition>
</template>

<script>
import * as pathTool from '@/pathTool'

export default {
  name: 'FileManager',
  components: {
  },
  watch: {
    $route: {
      immediate: true,
      async handler(to, from) {
        await this.loadData();
      }
    },
    showMkdirPopover(val) {
      if (val) {
        this.$nextTick(() => {
          this.$refs.mkdirName.focus();
        });
      } else {
        this.mkdirName = '';
      }
    },
  },
  methods: {
    async loadData(options) {
      options = options || {};
      if (options.isRefresh) {
        this.$store.commit('updateLoadStatus', false);
      };

      let _listQuery = this.dataFilter = this.T.createListQuery();
      let apiRes = await this.T.callAPI_get('/api/v1/resources/do/list', {
        query: _listQuery,
      });
      if (!apiRes || !apiRes.ok) return;

      let files = apiRes.data;
      let fileNameMap = {};
      files.forEach(f => {
        fileNameMap[f.name] = true;

        switch (f.type) {
          case 'folder':
            f.icon = 'folder-o';
            break;

          case 'file':
            f.icon = 'file-o';
            f.ext  = null;
            if (f.name.indexOf('.') > 0) {
              f.ext = f.name.split('.').pop();
            }

            if (f.size) {
              f.sizeHuman = this.T.byteSizeHuman(f.size);
            }

            f.previewURL = this.T.formatURL(`/api/v1/resources/do/download`, {
              baseURL: true,
              auth   : true,
              query  : { preview: true, filePath: this.getPath(f.name) },
            });
            f.downloadURL = this.T.formatURL(`/api/v1/resources/do/download`, {
              baseURL: true,
              auth   : true,
              query  : { filePath: this.getPath(f.name) },
            });
            break;
        }

        switch (f.ext) {
          case 'zip':
          case 'rar':
          case '7z':
          case 'tar':
          case 'bz':
          case 'gz':
            f.icon = 'file-archive-o';
            break;
          case 'htm':
          case 'html':
          case 'css':
          case 'js':
          case 'ts':
          case 'coffee':
          case 'py':
          case 'ipynb':
          case 'go':
          case 'java':
          case 'php':
          case 'pl':
          case 'sh':
          case 'rb':
          case 'lua':
          case 'kt':
          case 'r':
          case 'h':
          case 'c':
          case 'cpp':
          case 'cs':
          case 'm':
          case 'swift':
          case 'sql':
          case 'ini':
          case 'xml':
          case 'toml':
          case 'yaml':
          case 'json':
          case 'jsonl':
            f.icon = 'file-code-o';
            break;
          case 'jpg':
          case 'jpeg':
          case 'png':
          case 'gif':
          case 'bmp':
            f.icon = 'file-image-o';
            break;
          case 'pdf':
            f.icon = 'file-pdf-o';
            break;
          case 'txt':
          case 'csv':
          case 'md':
          case 'markdown':
            f.icon = 'file-text-o';
            break;
          case 'mp3':
            f.icon = 'file-audio-o';
            break;
          case 'avi':
          case 'mp4':
          case 'mkv':
            f.icon = 'file-video-o';
            break;
          case 'doc':
          case 'docx':
            f.icon = 'file-word-o';
            break;
          case 'xls':
          case 'xlsx':
            f.icon = 'file-excel-o';
            break;
          case 'ppt':
          case 'pptx':
            f.icon = 'file-powerpoint-o';
            break;
        }

        if (this.T.isNothing(_listQuery)) {
          if (f.type === 'folder') {
            let folderName = f.name;
            if (this.T.endsWith(folderName, '/')) {
              folderName = folder.slice(0, -1);
            }
            switch(folderName) {
              case this.$store.getters.SYSTEM_INFO('UPLOAD_TEMP_FILE_DIR'):
                f.tip = this.$t('Temp Folder for Upload');
                break;

              case this.$store.getters.SYSTEM_INFO('DOWNLOAD_TEMP_FILE_DIR'):
                f.tip = this.$t('Temp Folder for Download');
                break;

              case this.$store.getters.SYSTEM_INFO('_EXTRA_PYTHON_PACKAGE_INSTALL_DIR'):
                f.tip = this.$t('Python Package Folder for Installation via PIP Tool');
                break;

              case this.$store.getters.SYSTEM_INFO('_USER_PYTHON_PACKAGE_DIR'):
                f.tip = this.$t('Python Package Folder for Local Usage by User');
                break;

              case this.$store.getters.SYSTEM_INFO('_SCRIPT_MARKET_BASE_DIR'):
                f.tip = this.$t('Data Folder for Script Market');
                break;

              case this.$store.getters.SYSTEM_INFO('_PRE_RUN_SCRIPT_DIR'):
                f.tip = this.$t('Pre-Run Script Folder');
                break;
            }
          }
        }
      });

      // Default order
      files.sort(function(a, b) {
        if (a.type !== b.type) return a.type === 'folder' ? -1 : 1;
        if (a.name !== b.name) return a.name < b.name ? -1 : 1;
        return 0;
      });

      this.files       = files;
      this.fileNameMap = fileNameMap;

      this.$store.commit('updateLoadStatus', true);
    },
    getPath(name) {
      return pathTool.join(this.currentFolder, name);
    },
    enterFolder(name, isAbs) {
      if (!name) {
        this.dataFilter.folder = '/';
      } else {
        if (isAbs) {
          this.dataFilter.folder = name;
        } else {
          this.dataFilter.folder = this.getPath(name);
        }
      }

      this.T.changePageFilter(this.dataFilter);
    },
    async resourceOperationCmd(options){
      if (!options) return;

      let name      = options.data.name;
      let operation = options.operation;

      return await this.resourceOperation(name, operation)
    },
    async resourceOperation(name, operation) {
      // Before operation
      let operationArgument = null;
      switch(operation) {
        case 'cp':
          operationArgument = await this.T.prompt(this.$t('Please input destination path'), name);
          if (!operationArgument) return;
          break;

        case 'mv':
          operationArgument = await this.T.prompt(this.$t('Please input destination path'), `./${name}`);
          if (!operationArgument) return;
          break;

        case 'rm':
          if (!await this.T.confirm(this.$t('Are you sure you want to delete the content?'))) return;
          break;
      }

      // Operation is running
      let delayedLoadingT = setTimeout(() => {
        this.isProcessing = true;
      }, 200);

      // Do operation
      let apiRes = await this.T.callAPI('post', '/api/v1/resources/do/operate', {
        body : {
          targetPath       : this.getPath(name),
          operation        : operation,
          operationArgument: operationArgument,
        },
      });

      // Operation is finished
      clearTimeout(delayedLoadingT);
      this.isProcessing = false;

      if (!apiRes.ok) return this.loadData();

      // After operation
      switch(operation) {
        case 'mkdir':
          this.showMkdirPopover = false;
          this.mkdirName        = '';

          await this.enterFolder(name);
          break;

        default:
          await this.loadData();
          break;
      }
    },
    async handleUpload(req) {
      // Check file size
      let fileSizeLimit = this.$store.getters.SYSTEM_INFO('_RESOURCE_UPLOAD_FILE_SIZE_LIMIT');
      if (req.file.size > fileSizeLimit) {
        let sizeStr = this.T.byteSizeHuman(fileSizeLimit);
        return this.T.alert(this.$t('File too large (size limit: {size})', { size: sizeStr }));
      }

      var filename = req.file.name;
      var rename   = null;

      if (this.fileNameMap[filename]) {
        // File already exists
        let promptRes = null;
        try {
          // Rename to `xxx-2.ext` automatically
          let _filenameParts = filename.split('.');
          let fileExt = '';
          if (_filenameParts.length > 1) {
            fileExt = `.${_filenameParts.pop()}`;
          }
          let filenameNoExt = _filenameParts.join('.');

          let defaultRename = null;
          let seq = 2;
          while (true) {
            defaultRename = `${filenameNoExt}-${seq}${fileExt}`;
            if (!this.fileNameMap[defaultRename]) break;

            seq++;
          }

          // This input box needs to be checked for duplicate files
          promptRes = await this.$prompt(this.$t('File <code class="text-main">{name}</code> already existed, please input a new name', { name: filename }), this.$t('Upload'), {
            customClass             : 'uploadRename',
            inputValue              : defaultRename,
            dangerouslyUseHTMLString: true,
            closeOnClickModal       : false,
            confirmButtonText       : this.$t('Upload'),
            cancelButtonText        : this.$t('Cancel'),
            inputValidator: value => {
              if (this.fileNameMap[value]) {
                return this.$t('File already existed');
              }
            }
          });
        } catch(err) {
          this.$refs.upload.clearFiles();
          return; // Cancel
        }

        rename = promptRes.value;
      }

      let bodyData = new FormData();
      bodyData.append('files', req.file);
      bodyData.append('folder', this.dataFilter.folder || '.');
      if (rename) {
        bodyData.append('rename', rename);
      }

      // Operation is running
      let delayedLoadingT = setTimeout(() => {
        this.isProcessing = true;
      }, 200);

      // Do upload
      let prevProgressTimestamp = null;
      let prevProgressLoaded    = null;
      let _updateProgressTipFunc = this.T.throttle((progressTip) => {
        this.progressTip = progressTip;
      }, 500);
      let apiRes = await this.T.callAPI('post', '/api/v1/resources/do/upload', {
        body    : bodyData,
        feedback: { okMessage: this.$t('File uploaded') },
        onUploadProgress: (event) => {
          let progressTip = `${this.$t('Uploading {filename}', { filename: rename || filename })}`;
          if (prevProgressTimestamp && prevProgressLoaded) {
            let percent = (event.loaded / event.total * 100).toFixed(1);
            let speed   = (event.loaded - prevProgressLoaded) / (event.timeStamp - prevProgressTimestamp) * 1000;

            let cost = parseInt(event.timeStamp / 1000);
            let costText = this.$t('uploadCost', { s: cost });
            if (cost > 60) {
              let costMinutes = parseInt(cost / 60);
              let costSeconds = parseInt(cost % 60);
              costText = this.$t('uploadCostLong', { m: costMinutes, s: costSeconds });
            }

            progressTip += ` - `;
            progressTip += `${percent}%`
            progressTip += `${this.$t(',')}${this.T.byteSizeHuman(event.loaded)} / ${this.T.byteSizeHuman(event.total)}`
            progressTip += `${this.$t(',')}${this.T.byteSizeHuman(speed)}/s`
            progressTip += `${this.$t(',')}${this.$t('Cost')} ${costText}`;

            if (cost > 10) {
              let remain = parseInt((event.timeStamp / event.loaded * event.total - event.timeStamp) / 1000);
              let remainText = this.$t('uploadCost', { s: remain });
              if (remain > 60) {
                let remainMinutes = parseInt(remain / 60);
                let remainSeconds = parseInt(remain % 60);
                remainText = this.$t('uploadCostLong', { m: remainMinutes, s: remainSeconds });
              }

              progressTip += `${this.$t(',')}${this.$t('Remain')} ${remainText}`
            }
          }

          prevProgressTimestamp = event.timeStamp;
          prevProgressLoaded    = event.loaded;

          _updateProgressTipFunc(progressTip);
        },

        // No timeout for upload API
        timeout: false,
      });

      // Operation is finished
      clearTimeout(delayedLoadingT);
      this.isProcessing = false;
      this.progressTip  = '';

      await this.loadData();

      this.$refs.upload.clearFiles();
    },
    onUploadFileChange(file, fileList) {
      if (fileList.length > 1) fileList.splice(0, 1);
    },
    openInstallWheel(name) {
      this.wheelToInstall = name;
      this.pipIndexURL    = this.C.PIP_MIRROR_DEFAULT.value;

      this.showInstallWheel = true;
    },
    async installWheel() {
      let name = this.wheelToInstall;

      // Operation is running
      let delayedLoadingT = setTimeout(() => {
        this.isProcessing = true;
      }, 200);

      let apiRes = await this.T.callAPI('post', '/api/v1/python-packages/do/install', {
        body : {
          pipIndexURL: this.pipIndexURL,
          packages   : this.getPath(name),
        },
        feedback: { okMessage: this.$t('Wheel package installed: {name}', { name: name }) },
      });

      // Operation is finished
      clearTimeout(delayedLoadingT);
      this.isProcessing     = false;
      this.showInstallWheel = false;
    },
  },
  computed: {
    previewExts() {
      return [
        'jpg', 'jpeg',
        'png',
        'bmp',
        'gif',
        'mp3','mp4',
        'pdf',
        'txt',
        'htm', 'html',
        'json',
        'md', 'markdown',
      ]
    },
    archiveExts() {
      return [
        'zip',
        'tar',
        'gz',
        'bz',
        '7z',
      ]
    },
    currentFolder() {
      return this.dataFilter.folder || '/';
    },
  },
  props: {
  },
  data() {
    let _dataFilter = this.T.createListQuery();

    return {
      files      : [],
      fileNameMap: {},

      showMkdirPopover: false,
      mkdirName       : '',

      showInstallWheel : false,
      wheelToInstall   : '',
      pipIndexURL      : '',

      isProcessing: false,
      progressTip : '',

      dataFilter: {
        folder: _dataFilter.folder,
      }
    }
  },
}
</script>

<style scoped>
.file-folder-name {
  font-size: 16px;
}
.resource-navi .el-button {
  margin-left: 0 !important;
  padding: 5px 5px !important;
}
.popover-input {
  display: flex;
  align-items: center;
  justify-content: space-around;
}
.upload-button {
  display: inline-block;
}
.path-sep {
  width: 20px;
  text-align: center;
  display: inline-block;
  font-size: 14px;
}
</style>

<style>
.popover-input .el-input {
  width: 180px;
  display: block;
}
</style>
